package com.bosssoft.cloud.wechat.infrastructure.util;

import com.bosssoft.cloud.wechat.infrastructure.enums.ErrEnum;
import com.bosssoft.cloud.wechat.infrastructure.exception.BusinessException;
import com.bosssoft.cloud.wechat.infrastructure.exception.SystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author wcy create on 2021/5/27 14:44 下午
 */
public class ReflectUtil {
    private static final Logger logger = LoggerFactory.getLogger(ReflectUtil.class);

    /**
     * 处理加了注解的参数，目前用不上
     *
     * @param <T>  T
     * @param data bean
     */
    public static <T> void handle(T data) throws IllegalAccessException {
        if (data == null) return;
        Class<?> clazz = data.getClass();
        List<Field> fields = getFieldsCallSuper(clazz);
        for (Field f : fields) {
            Annotation[] ins = f.getDeclaredAnnotations();
            for (Annotation in : ins) {
                /*
                处理do something
                 */
            }
        }
    }

    /**
     * 获取包括父类的所有field
     *
     * @param clazz clazz
     * @return fields
     */
    public static List<Field> getFieldsCallSuper(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null) {
            fields.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    /**
     * 获取属性名数组
     *
     * @param o 对象
     * @return 属性名
     */
    public static String[] getFiledNames(Object o) {
        Field[] fields = o.getClass().getDeclaredFields();
        String[] fieldNames = new String[fields.length];
        for (int i = 0; i < fields.length; i++) {
            // 获取属性名
            fieldNames[i] = fields[i].getName();
        }
        return fieldNames;
    }

    /**
     * 根据对象的属性名，执行对应get方法
     *
     * @param obj       对象
     * @param paramName 属性名
     * @return 执行方法后的返回值
     */
    @SuppressWarnings("unchecked")
    public static <R, T> T get(R obj, String paramName) {
        try {
            PropertyDescriptor pd = new PropertyDescriptor(paramName, obj.getClass());
            Method method = pd.getReadMethod();
            method.setAccessible(true);
            return (T) method.invoke(obj);
        } catch (IllegalAccessException | IntrospectionException | InvocationTargetException e) {
            throw new SystemException(ErrEnum.B0410,
                    String.format("ReflectUtil.get错误:%s获取属性%s失败,或该属性的GET方法执行失败。",
                            obj.getClass(), paramName));
        }
    }

    /**
     * 根据对象的属性名，执行对应set方法
     *
     * @param obj       对象
     * @param paramName 属性名
     */
    public static <R> void set(R obj, String paramName, Object value) {
        try {
            PropertyDescriptor pd = new PropertyDescriptor(paramName, obj.getClass());
            Method method = pd.getWriteMethod();
            method.setAccessible(true);
            method.invoke(obj, value);
        } catch (IllegalAccessException | IntrospectionException | InvocationTargetException e) {
            throw new SystemException(ErrEnum.B0410,
                    String.format("ReflectUtil.set错误:%s设置属性%s失败,或该属性的SET方法执行失败。",
                            obj.getClass(), paramName));
        }
    }

    /**
     * 获取set方法名
     *
     * @param name 属性名
     * @return 属性对应的set方法名
     */
    public static String getSetMethodName(String name) {
        return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
    }

    /**
     * 参数值类型转换
     *
     * @param declaredField field
     * @param value         要转换的值
     * @return 转换后的值
     */
    public static Object processFiledType(Field declaredField, String value) {
        Object resultValue = value;
        String fieldType = declaredField.getType().getName();
        try {
            if (Objects.equals(fieldType, Integer.class.getName())) {
                resultValue = Integer.valueOf(value);
            } else if (Objects.equals(fieldType, String.class.getName())) {
                resultValue = value;
            } else if (Objects.equals(fieldType, Byte.class.getName())) {
                resultValue = Byte.valueOf(value);
            } else if (Objects.equals(fieldType, Long.class.getName())) {
                resultValue = Long.valueOf(value);
            } else if (Objects.equals(fieldType, Double.class.getName())) {
                resultValue = Double.valueOf(value);
            }
        } catch (Exception e) {
            throw new BusinessException(ErrEnum.A0402);
        }
        return resultValue;
    }
}
